/*
                              Decompression File
			      
	This file is used to Decompress the file which is compressed by the
Compression utility provided only by us.This program takes Compressed file 
name as Input parameter and decompresses it.	

 */
//=============================================================================
//Block of header files used in Program
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<time.h>
#include<malloc.h>
//=============================================================================
//Global variables used in Program
unsigned int ENO=4294967168;
//=============================================================================
//Data structures used in Program to manipulate the Header
struct header
{
   char ch;
   unsigned long code;
   unsigned int depth;
   unsigned int tot_node;
   struct header *next;
};
//=============================================================================
//This function is used to display size two files i.e.Compress & Uncompress
void ratio(fnmR,fnmW)
char fnmR[15];
char fnmW[15];
{
	struct stat statbuf;
	stat(fnmR,&statbuf);
	printf("\n%s File Size is %ld\n",fnmR,statbuf.st_size);
	printf("File Last accessed %s",ctime(&statbuf.st_ctime));
	
	stat(fnmW,&statbuf);
	printf("\nAfter Decompression File name is %s\n",fnmW);
	printf("File Size is %ld\n",statbuf.st_size);	    	
	printf("Last File accessed %s\n",ctime(&statbuf.st_ctime)); 
}
//=============================================================================
//This function is used to bring the exceding nos in range
unsigned long excedify(no)
unsigned long no;
{
	int rem=0;
	if(no>ENO)
	{
		rem=no-ENO;
		no=128+rem;
	}
	if(no==ENO)
		no=128;
	return no;
}
//=============================================================================
//This function is used to Construct the Header
void reconstruct_header(head,chr,chr_code,chr_depth)
struct header **head;
char chr;
unsigned long chr_code;
unsigned int chr_depth;
{
   struct header *temp=*head,*temp1;
   if(*head==NULL)
   {
     temp=(struct header *)malloc(sizeof(struct header));
     temp->ch=chr;
     temp->code=chr_code;
     temp->depth=chr_depth;
     temp->tot_node=1;
     temp->next=NULL;
     *head=temp;
   }
   else
   {
     while(temp->next!=NULL)
       temp=temp->next;

     temp1=(struct header *)malloc(sizeof(struct header));
     temp1->ch=chr;
     temp1->code=chr_code;
     temp1->depth=chr_depth;
     temp1->tot_node=-1;
     temp1->next=NULL;
     temp->next=temp1;
     (*head)->tot_node++;
   }
}
//=============================================================================
int decompress(fnmR)
char fnmR[15];
{
//Block of local variables used in Decompression
  int fpW,fpR;
  unsigned int byt_read,chr_depth,chk_depth;
  unsigned long chr_code,chk_code,comp_code;
  unsigned int temp_file_size=0,temp_chr_code=0;
  unsigned int rem_code,temp_chk=0,prev=0,mult,temp_code=0;
  unsigned int temp_header_size;
  int cnt,x,byte_cnt,rem_depth,i,j;
  unsigned long org_file_size=0,total_node=0,new_file_size=0;
  unsigned long tmp=0,rem=0,header_size=0;
  char *ch,fnmW[20],*comp_file_ext,chr,*comp_byte,uch,lch;
  struct header *head=NULL,*temp;
//=============================================================================

  if((fpR=open(fnmR,O_RDONLY))==-1)
  {
     printf("\n %s File cann't be open",fnmR);
     exit(0);
  }
  else
  {
    //Reading the TotalNos of Node for header of from Input File
    ch=(char *)malloc(1);
    read(fpR,ch,1);
    tmp=(unsigned int) (*ch);
    tmp=excedify(tmp);
    tmp=tmp<<8;
    tmp=tmp>>8;
    total_node=tmp;   
    
    ch=(char *)malloc(1);
    read(fpR,ch,1);
    tmp=(unsigned int) (*ch);
    tmp=excedify(tmp);
    tmp=tmp<<8;
    tmp=tmp>>8;
    if(total_node!=0)
    {
      total_node=total_node<<8;
      total_node=total_node|tmp;
    }
    else
     total_node=tmp;
    //End of reading TotalNos. of Nodes
//=============================================================================
    //Reading the extension of Original File
    comp_file_ext=(char *)malloc(4);
    read(fpR,comp_file_ext,3);
    comp_file_ext[3]='\0';
    if(strcmp(comp_file_ext,"svv")==0)
	    comp_file_ext=NULL;
    //End of reading Extension
//=============================================================================
    //Read Original File size from Input File
    org_file_size=0;
    temp_file_size=0;
    byte_cnt=3;

    while(byte_cnt>=0)
    {
      ch=(char *)malloc(1);
      read(fpR,ch,1);
      temp_file_size=(unsigned int)(*ch);
      temp_file_size=excedify(temp_file_size);
      temp_file_size=temp_file_size<<8;
      temp_file_size=temp_file_size>>8;

      org_file_size=org_file_size<<8;
      org_file_size=org_file_size|temp_file_size;
      temp_file_size=0;

      byte_cnt=byte_cnt-1;
    }
    //End of Reading Original File size
//=============================================================================
    //Reading Header size from Input File
    header_size=0;
    temp_header_size=0;
    byte_cnt=3;

    while(byte_cnt>=0)
    {
      ch=(char *)malloc(1);
      read(fpR,ch,1);
      temp_header_size=(unsigned int)(*ch);
      temp_header_size=excedify(temp_header_size);
      temp_header_size=temp_header_size<<8;
      temp_header_size=temp_header_size>>8;

      header_size=header_size<<8;
      header_size=header_size|temp_header_size;
      temp_header_size=0;

      byte_cnt=byte_cnt-1;
    }
    //End of reading header size
//=============================================================================
    //Each Header node has sequence as
    //1 bytes char 1 bytes depth and next bytes code
    //Reading one by one and constructing Header Node and Header
    byt_read=0;
    chr_code=0;
    while(header_size>byt_read)
    {
      //Readinng Character	    
      ch=(char *)malloc(1);
      read(fpR,ch,1);
      chr=(char)(*ch);
      free(ch);
      
      //increase nos of bytes read
      byt_read=byt_read+1;
      
      //Reading Depth
      ch=(char *)malloc(1);
      read(fpR,ch,1);
      chr_depth=(unsigned int)(*ch);
      
      //increase nos of bytes read
      byt_read=byt_read+1;
      
      //calculate code bytes 
      if(chr_depth>8)
      {
	cnt=chr_depth/8;
	if ((chr_depth%8)>0)
	  cnt=cnt+1;
         
	//Reading code bytes
	for(cnt=cnt-1;cnt>=0;cnt--)
	{
	 ch=(char *)malloc(1);
	 read(fpR,ch,1);
	 byt_read=byt_read+1;
	 temp_chr_code=(unsigned int)(*ch);
	 temp_chr_code=excedify(temp_chr_code);
	 temp_chr_code=temp_chr_code<<8;
	 temp_chr_code=temp_chr_code>>8;
	 chr_code=chr_code<<8;
	 chr_code=chr_code|temp_chr_code;
	}
      }
      //end of Depth > 8 
      else
      {
        ch=(char *)malloc(1);
        read(fpR,ch,1);
        byt_read=byt_read+1;
	chr_code=(unsigned int)(*ch);
	chr_code=excedify(chr_code);
        chr_code=chr_code<<8;
	chr_code=chr_code>>8;
      }
      //end of depth <= 8
      chr_code=chr_code<<(16-chr_depth);
      chr_code=chr_code>>(16-chr_depth);
      //Reconstructing Header 
      reconstruct_header(&head,chr,chr_code,chr_depth);
      chr_code=0;
    }

    if(head->tot_node != total_node)
    {
       printf("\nFail Header is Corrupted");
       exit(0);
    }
    //End of creation of header
//==============================================================================
    //Start to constuct New file
    //Construct file name for New file
    sscanf(fnmR,"%[^.]s",fnmW);
    strcat(fnmW,"1");
    if(comp_file_ext!=NULL)
    {
     strcat(fnmW,".");
     strcat(fnmW,comp_file_ext);
    }
    if((fpW=open(fnmW,O_CREAT|O_WRONLY|O_TRUNC,S_IWRITE))==-1)
    {
       printf("New File Opening Error");
       exit(0);
    }
    else
    {
     comp_byte=(char *)malloc(1);
     chk_depth=0;

     while(1)
     {
      //Read Each compressed byte from Input File and 
      //Convert to  appropriate character
      x=read(fpR,comp_byte,1);
      
      if(x==0)//End of Input File : Terminating Condition
       break;
      
      comp_code=0;
      rem=0;  
      //Convert read byte to code and check
      comp_code=(unsigned int)(*comp_byte);
      comp_code=excedify(comp_code);
      comp_code=comp_code<<8;
      comp_code=comp_code>>8;
      cnt=7;
      //Construct check code 
      if(chk_depth!=0)
      {
       chk_code=excedify(chk_code);
       chk_code=chk_code<<8;
       chk_code=excedify(chk_code);
       chk_code=chk_code|comp_code;
       chk_code=excedify(chk_code);
       cnt=cnt+chk_depth;
       comp_code=chk_code;
       chk_depth=0;
      }
      while(cnt>=0)
      {
       chk_code=excedify(chk_code);
       chk_code=comp_code>>cnt;
       chk_code=excedify(chk_code);
       chk_depth=chk_depth+1;
       temp_chk=chk_code;
       temp_chk=excedify(temp_chk);
       //Check check code with Header Nodes
       temp=head;
       while(temp!=NULL)
       {
	if(temp->code==temp_chk && temp->depth==chk_depth)
	{
	 *ch=temp->ch;
	 //Cheacking the new File size with Original File
	 //Terminate accordingly if equal
	 if(new_file_size==org_file_size)
	 {
	    printf("\nFile is Uncompressed Successfully with %s name\n",fnmW);
	    fcloseall();
	    return(0);
	 }
	 //Writing matching character to New file
	 if(write(fpW,ch,1)!=1)
	 {
	   printf("\nFile Writting Error");
	   exit(0);
	 }
	 else
	 {
           //Retriving remaining code form check code
           temp_code=comp_code;
           prev=0;
           mult=1; 
           for(i=0;i<cnt;i++)
           {
             rem=temp_code&1;
             temp_code=temp_code>>1;
             mult=1;
             for(j=i;j>0;j--)
             {
               mult=mult*2;
             }
             prev=prev+(rem*mult);
           } 
	   
           comp_code=prev;
           prev=0;
	   comp_code=excedify(comp_code);
	   chk_code=0;
	   chk_depth=0;
	   //Keep Track of new File size
	   new_file_size=new_file_size+1;
	 }
	 break;
	}
	//End of if depth & code cheaking
	temp=temp->next;
       } 
       //End of head temp while
       cnt--;
      }
      //End of while cnt>0
     }
     //End of while(1)
    }
    //End of else of writting new file
  }
  //End of else of file open fnmR
  fcloseall();
 return 0;
}
//End of Decompression of Input File
//=============================================================================
//Start of Program : Entry Point
int main(int argc,char *argv[])
{
	char fnmW[15],*ch,*comp_file_ext;
	unsigned long org_file_size=0;
	unsigned int  temp_file_size=0;  
	int byte_cnt,fpR;
	system("clear");
	switch(argc)
	{
		case 1:
			printf("Insufficient Arguments");
			break;
                case 2:
			if(strcmp(argv[1],"-help")==0)
			{
				system("clear");
				system("cat Uncompress.man");
			}
			else if(strcmp(argv[1],"-info")==0)
			{
				system("clear");
				system("cat info.info");
			}
			else
			   decompress(argv[1]);
			break;
		case 3:
			if(strcmp(argv[2],"-i")==0)
			{
                          
                          if((fpR=open(argv[1],O_RDONLY))==-1)
			  {
                              printf("\n %s File cann't be open",argv[1]);
			      exit(0);
			  }
                          else
                          {
                           ch=(char *)malloc(2);
                           if(read(fpR,ch,2)!=2)
			   {
			    printf("\nError in Reading File %s \n",argv[1]);
			    exit(0);
			   }
			   //Reading the extension of Original File
                           comp_file_ext=(char *)malloc(4);
                           if(read(fpR,comp_file_ext,3)!=3)
			   {
			    printf("\nError in Reading File %s \n",argv[1]);
			    exit(0);
			   }
			   comp_file_ext[3]='\0';
			   if(strcmp(comp_file_ext,"svv")==0)
			      comp_file_ext=NULL;
                           //End of reading Extension
                           //Construct file name for New file
                           sscanf(argv[1],"%[^.]s",fnmW);
                           strcat(fnmW,"1");
			   if(comp_file_ext!=NULL)
			   {
                            strcat(fnmW,".");
                            strcat(fnmW,comp_file_ext);
			   }
                           //Read Original File size from Input File
                           org_file_size=0;
                           temp_file_size=0;
                           byte_cnt=3;

                           while(byte_cnt>=0)
                           {
                             ch=(char *)malloc(1);
                             if(read(fpR,ch,1)!=1)
			     {
			        printf("\nError in reading File %s\n",argv[1]);
				exit(0);
			     }
                             temp_file_size=(unsigned int)(*ch);
			     temp_file_size=excedify(temp_file_size);
                             temp_file_size=temp_file_size<<8;
                             temp_file_size=temp_file_size>>8;

                             org_file_size=org_file_size<<8;
                             org_file_size=org_file_size|temp_file_size;
                             temp_file_size=0;

                             byte_cnt=byte_cnt-1;
                            }
                            //End of Reading Original File size
			  }
		     printf("\nDecompressed File will Have name as %s ",fnmW);
		     printf("\nAnd Size is of %ld bytes\n",org_file_size);
			}
			//End of argv[2] is "-i"
			
			else if(strcmp(argv[2],"-r")==0)
			{
			  decompress(argv[1]);
                          if((fpR=open(argv[1],O_RDONLY))==-1)
			  {
                              printf("\n %s File cann't be open",argv[1]);
			      exit(0);
			  }
                          else
                          {
                           ch=(char *)malloc(2);
                           if(read(fpR,ch,2)!=2)
			   {
			    printf("\nError in Reading File %s \n",argv[1]);
			    exit(0);
			   }
			   //Reading the extension of Original File
                           comp_file_ext=(char *)malloc(4);
                           if(read(fpR,comp_file_ext,3)!=3)
			   {
			    printf("\nError in Reading File %s \n",argv[1]);
			    exit(0);
			   }
			   comp_file_ext[3]='\0';
			   
			   if(strcmp(comp_file_ext,"svv")==0)
			      comp_file_ext=NULL;
			   
                           //End of reading Extension
                           //Construct file name for New file
                           sscanf(argv[1],"%[^.]s",fnmW);
                           strcat(fnmW,"1");
			   if(comp_file_ext!=NULL)
			   {
                             strcat(fnmW,".");
                             strcat(fnmW,comp_file_ext);
			   }
                           //Read Original File size from Input File
                           org_file_size=0;
			   
			  }
			 ratio(argv[1],fnmW);
			}
			//End of argv[2] is "-r"
			else
			{
				printf("\nInavalid Command\n");
				exit(0);
			}
			break;
		default :
			printf("\nInvalid Command\n");
			break;
	}
	return 0;
}
//End of Program
//=============================================================================
